package com.zj.base.permission.manifests;


import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AppOpsManager;
import android.app.usage.UsageStatsManager;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.hardware.Camera;
import android.location.Location;
import android.location.LocationManager;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Binder;
import android.os.Build;
import android.os.Environment;
import android.provider.ContactsContract;
import android.text.TextUtils;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import static android.os.Build.VERSION_CODES.KITKAT;

/**
 * Created by zhaojie on 2018/5/23.
 */

@SuppressWarnings("unused")
public final class Op_PermissionCheekUtils {


    /**
     * 将现有方法暴露并执行，为了方便配置（实际检测需要匹配对应方法）
     *
     * @param activity
     * @param name     the configuration modules declared method name
     * @param opName   the name with OP_Manifest
     * @see Manifest
     */
    public static synchronized boolean invokeDeclaredMethod(Activity activity, String name, String opName) {
        try {
            if (TextUtils.isEmpty(name))
                throw new IllegalStateException("you still not config any methods by this name :" + name + "& opName = " + opName);
            Class cls = Op_PermissionCheekUtils.class;
            Method[] methods = cls.getDeclaredMethods();
            for (Method method : methods) {
                if (method.getName().equals(name)) {
                    Object result = method.invoke(cls.newInstance(), activity);
                    return (boolean) result;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return declaredWithOpName(activity, opName);
    }

    /**
     * 使用配置清单查询
     */
    private static boolean declaredWithOpName(Activity activity, String opName) {
        if (TextUtils.isEmpty(opName)) return false;
        int opCode = getDeclaredPermissionCode(opName);
        return isPermissionGranted(activity, opCode);
    }

    /**
     * 实测相机是否可用
     */
    private boolean isCameraUse(Activity activity) {
        try {
            Camera camera = Camera.open();
            camera.release();
            return Build.VERSION.SDK_INT < KITKAT || isPermissionGranted(activity, getDeclaredPermissionCode(Manifest.OP_CAMERA));
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 实测文件储存是否可用
     */
    private boolean isExternalStorageUsed(Activity activity) {
        String path;
        File file = null;
        try {
            path = Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "hasFilePermissions.txt";
            file = new File(path);
            if (!file.exists()) file.mkdirs();
            return file.exists();
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        } finally {
            if (file != null && file.exists()) file.delete();
        }
    }

    /**
     * 实测获取联系人信息
     */
    private boolean isReadConstantsUse(Activity activity) {
        ContentResolver resolver = activity.getContentResolver();
        Cursor cursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
        if (cursor != null)
            cursor.close();
        return Build.VERSION.SDK_INT < KITKAT || isPermissionGranted(activity, getDeclaredPermissionCode(Manifest.OP_READ_CONTACTS));
    }

    /**
     * 实测定位权限
     */
    @SuppressLint("MissingPermission")
    private boolean isLocationUse(Activity activity) {
        try {
            LocationManager manager = (LocationManager) activity.getSystemService(Context.LOCATION_SERVICE);
            String provider = LocationManager.NETWORK_PROVIDER;
            if (manager != null) {
                Location location = manager.getLastKnownLocation(provider);
            }
            if (Build.VERSION.SDK_INT >= KITKAT) {
                boolean isCoarse = isPermissionGranted(activity, getDeclaredPermissionCode(Manifest.OP_COARSE_LOCATION));
                boolean isFine = isPermissionGranted(activity, getDeclaredPermissionCode(Manifest.OP_FINE_LOCATION));
                return isCoarse && isFine;
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 实测录音是否可用
     */
    public synchronized boolean isVoicePermission(Activity activity) {
        AudioRecord record = null;
        try {
            record = new AudioRecord(MediaRecorder.AudioSource.MIC, 22050,
                    AudioFormat.CHANNEL_IN_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT,
                    AudioRecord.getMinBufferSize(22050,
                            AudioFormat.CHANNEL_IN_STEREO,
                            AudioFormat.ENCODING_PCM_16BIT));
            record.startRecording();
            int recordingState = record.getRecordingState();
            if (recordingState == AudioRecord.RECORDSTATE_STOPPED) {
                return false;
            }
            record.release();
            record = new AudioRecord(MediaRecorder.AudioSource.MIC, 22050,
                    AudioFormat.CHANNEL_IN_STEREO,
                    AudioFormat.ENCODING_PCM_16BIT,
                    AudioRecord.getMinBufferSize(22050,
                            AudioFormat.CHANNEL_IN_STEREO,
                            AudioFormat.ENCODING_PCM_16BIT));
            record.startRecording();
            int recordingState1 = record.getRecordingState();
            if (Build.VERSION.SDK_INT >= KITKAT) {
                boolean isAlarm = isPermissionGranted(activity, getDeclaredPermissionCode(Manifest.OP_AUDIO_ALARM_VOLUME));
                boolean isAccessAble = isPermissionGranted(activity, getDeclaredPermissionCode(Manifest.OP_AUDIO_ACCESSIBILITY_VOLUME));
                return isAlarm && isAccessAble;
            }
            return true;
        } catch (Exception e) {
            return false;
        } finally {
            if (record != null) {
                record.release();
            }
        }

    }

    /**
     * 获取google隐藏的6。0以下权限检测方法，并检测权限；
     **/
    @TargetApi(KITKAT)
    private static boolean isPermissionGranted(Activity activity, int permissionCode) {
        AppOpsManager manager = (AppOpsManager) activity.getSystemService(Context.APP_OPS_SERVICE);
        if (manager == null) {
            return false;
        }
        try {
            Class c = manager.getClass();
            Class[] cArg = new Class[3];
            cArg[0] = int.class;
            cArg[1] = int.class;
            cArg[2] = String.class;
            Method method = c.getDeclaredMethod("checkOp", cArg);
            if (method != null) {
                int grandit = (int) method.invoke(manager, permissionCode, Binder.getCallingUid(), activity.getPackageName());
                return grandit == 0;
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return false;
    }

    @TargetApi(KITKAT)
    private static int getDeclaredPermissionCode(String name) {
        int fieldExtra = -1;
        try {
            Class clazz = AppOpsManager.class;
            Field field = clazz.getDeclaredField(name);
            fieldExtra = field.getInt(int.class);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return fieldExtra;
    }

    /**
     * 通过相似名称反射到OP类，查询当前授权代号（每个版本可能都不一样）
     */
    public static final class Manifest {
        /**
         * No operation specified.
         */
        public static final String NONE = "OP_NONE";
        /**
         * Access to coarse location information.
         */
        public static final String OP_COARSE_LOCATION = "OP_COARSE_LOCATION";
        /**
         * Access to fine location information.
         */
        public static final String OP_FINE_LOCATION = "OP_FINE_LOCATION";
        /**
         * Causing GPS to run.
         */
        public static final String OP_GPS = "OP_GPS";
        /**  */
        public static final String OP_VIBRATE = "OP_VIBRATE";
        /**  */
        public static final String OP_READ_CONTACTS = "OP_READ_CONTACTS";
        /**  */
        public static final String OP_WRITE_CONTACTS = "OP_WRITE_CONTACTS";
        /**  */
        public static final String OP_READ_CALL_LOG = "OP_READ_CALL_LOG";
        /**  */
        public static final String OP_WRITE_CALL_LOG = "OP_WRITE_CALL_LOG";
        /**  */
        public static final String OP_READ_CALENDAR = "OP_READ_CALENDAR";
        /**  */
        public static final String OP_WRITE_CALENDAR = "OP_WRITE_CALENDAR";
        /**  */
        public static final String OP_WIFI_SCAN = "OP_WIFI_SCAN";
        /**  */
        public static final String OP_POST_NOTIFICATION = "OP_POST_NOTIFICATION";
        /**  */
        public static final String OP_NEIGHBORING_CELLS = "OP_NEIGHBORING_CELLS";
        /**  */
        public static final String OP_CALL_PHONE = "OP_CALL_PHONE";
        /**  */
        public static final String OP_READ_SMS = "OP_READ_SMS";
        /**  */
        public static final String OP_WRITE_SMS = "OP_WRITE_SMS";
        /**  */
        public static final String OP_RECEIVE_SMS = "OP_RECEIVE_SMS";
        /**  */
        public static final String OP_RECEIVE_EMERGECY_SMS = "OP_RECEIVE_EMERGECY_SMS";
        /**  */
        public static final String OP_RECEIVE_MMS = "OP_RECEIVE_MMS";
        /**  */
        public static final String OP_RECEIVE_WAP_PUSH = "OP_RECEIVE_WAP_PUSH";
        /**  */
        public static final String OP_SEND_SMS = "OP_SEND_SMS";
        /**  */
        public static final String OP_READ_ICC_SMS = "OP_READ_ICC_SMS";
        /**  */
        public static final String OP_WRITE_ICC_SMS = "OP_WRITE_ICC_SMS";
        /**  */
        public static final String OP_WRITE_SETTINGS = "OP_WRITE_SETTINGS";
        /**  */
        public static final String OP_SYSTEM_ALERT_WINDOW = "OP_SYSTEM_ALERT_WINDOW";
        /**  */
        public static final String OP_ACCESS_NOTIFICATIONS = "OP_ACCESS_NOTIFICATIONS";
        /**  */
        public static final String OP_CAMERA = "OP_CAMERA";
        /**  */
        public static final String OP_RECORD_AUDIO = "OP_RECORD_AUDIO";
        /**  */
        public static final String OP_PLAY_AUDIO = "OP_PLAY_AUDIO";
        /**  */
        public static final String OP_READ_CLIPBOARD = "OP_READ_CLIPBOARD";
        /**  */
        public static final String OP_WRITE_CLIPBOARD = "OP_WRITE_CLIPBOARD";
        /**  */
        public static final String OP_TAKE_MEDIA_BUTTONS = "OP_TAKE_MEDIA_BUTTONS";
        /**  */
        public static final String OP_TAKE_AUDIO_FOCUS = "OP_TAKE_AUDIO_FOCUS";
        /**  */
        public static final String OP_AUDIO_MASTER_VOLUME = "OP_AUDIO_MASTER_VOLUME";
        /**  */
        public static final String OP_AUDIO_VOICE_VOLUME = "OP_AUDIO_VOICE_VOLUME";
        /**  */
        public static final String OP_AUDIO_RING_VOLUME = "OP_AUDIO_RING_VOLUME";
        /**  */
        public static final String OP_AUDIO_MEDIA_VOLUME = "OP_AUDIO_MEDIA_VOLUME";
        /**  */
        public static final String OP_AUDIO_ALARM_VOLUME = "OP_AUDIO_ALARM_VOLUME";
        /**  */
        public static final String OP_AUDIO_NOTIFICATION_VOLUME = "OP_AUDIO_NOTIFICATION_VOLUME";
        /**  */
        public static final String OP_AUDIO_BLUETOOTH_VOLUME = "OP_AUDIO_BLUETOOTH_VOLUME";
        /**  */
        public static final String OP_WAKE_LOCK = "OP_WAKE_LOCK";
        /**
         * Continually monitoring location data.
         */
        public static final String OP_MONITOR_LOCATION = "OP_MONITOR_LOCATION";
        /**
         * Continually monitoring location data with a relatively high power request.
         */
        public static final String OP_MONITOR_HIGH_POWER_LOCATION = "OP_MONITOR_HIGH_POWER_LOCATION";
        /**
         * Retrieve current usage stats via {@link UsageStatsManager}.
         */
        public static final String OP_GET_USAGE_STATS = "OP_GET_USAGE_STATS";
        /**  */
        public static final String OP_MUTE_MICROPHONE = "OP_MUTE_MICROPHONE";
        /**  */
        public static final String OP_TOAST_WINDOW = "OP_TOAST_WINDOW";
        /**
         * Capture the device's display contents and/or audio
         */
        public static final String OP_PROJECT_MEDIA = "OP_PROJECT_MEDIA";
        /**
         * Activate a VPN connection without user intervention.
         */
        public static final String OP_ACTIVATE_VPN = "OP_ACTIVATE_VPN";
        /**
         * Access the WallpaperManagerAPI to write wallpapers.
         */
        public static final String OP_WRITE_WALLPAPER = "OP_WRITE_WALLPAPER";
        /**
         * Received the assist structure from an app.
         */
        public static final String OP_ASSIST_STRUCTURE = "OP_ASSIST_STRUCTURE";
        /**
         * Received a screenshot from assist.
         */
        public static final String OP_ASSIST_SCREENSHOT = "OP_ASSIST_SCREENSHOT";
        /**
         * Read the phone state.
         */
        public static final String OP_READ_PHONE_STATE = "OP_READ_PHONE_STATE";
        /**
         * Add voicemail messages to the voicemail content provider.
         */
        public static final String OP_ADD_VOICEMAIL = "OP_ADD_VOICEMAIL";
        /**
         * Access APIs for SIP calling over VOIP or WiFi.
         */
        public static final String OP_USE_SIP = "OP_USE_SIP";
        /**
         * Intercept outgoing calls.
         */
        public static final String OP_PROCESS_OUTGOING_CALLS = "OP_PROCESS_OUTGOING_CALLS";
        /**
         * User the fingerprint API.
         */
        public static final String OP_USE_FINGERPRINT = "OP_USE_FINGERPRINT";
        /**
         * Access to body sensors such as heart rate, etc.
         */
        public static final String OP_BODY_SENSORS = "OP_BODY_SENSORS";
        /**
         * Read previously received cell broadcast messages.
         */
        public static final String OP_READ_CELL_BROADCASTS = "OP_READ_CELL_BROADCASTS";
        /**
         * Inject mock location into the system.
         */
        public static final String OP_MOCK_LOCATION = "OP_MOCK_LOCATION";
        /**
         * Read external storage.
         */
        public static final String OP_READ_EXTERNAL_STORAGE = "OP_READ_EXTERNAL_STORAGE";
        /**
         * Write external storage.
         */
        public static final String OP_WRITE_EXTERNAL_STORAGE = "OP_WRITE_EXTERNAL_STORAGE";
        /**
         * Turned on the screen.
         */
        public static final String OP_TURN_SCREEN_ON = "OP_TURN_SCREEN_ON";
        /**
         * Get device accounts.
         */
        public static final String OP_GET_ACCOUNTS = "OP_GET_ACCOUNTS";
        /**
         * Control whether an application is allowed to run in the background.
         */
        public static final String OP_RUN_IN_BACKGROUND = "OP_RUN_IN_BACKGROUND";
        /**  */
        public static final String OP_AUDIO_ACCESSIBILITY_VOLUME = "OP_AUDIO_ACCESSIBILITY_VOLUME";
        /**
         * Read the phone number.
         */
        public static final String OP_READ_PHONE_NUMBERS = "OP_READ_PHONE_NUMBERS";
        /**
         * Request package installs through package installer
         */
        public static final String OP_REQUEST_INSTALL_PACKAGES = "OP_REQUEST_INSTALL_PACKAGES";
        /**
         * Enter picture-in-picture.
         */
        public static final String OP_PICTURE_IN_PICTURE = "OP_PICTURE_IN_PICTURE";
        /**
         * Instant app start foreground service.
         */
        public static final String OP_INSTANT_APP_START_FOREGROUND = "OP_INSTANT_APP_START_FOREGROUND";
        /**
         * Answer incoming phone calls
         */
        public static final String OP_ANSWER_PHONE_CALLS = "OP_ANSWER_PHONE_CALLS";
        /**  */
        public static final String _NUM_OP = "_NUM_OP";
    }
}
